#include <SFML/Graphics/RenderTarget.hpp>
#include <nice2d/text.h>
#include <nice2d/util.h>
#include <nice2d/application.h>
#include <nice2d/texthelper.h>
#include <nice2d/tostring.h>
#include <nice2d/components/fontmanager.h>

#define TEXT_MARGIN 3.0f

class TextData
{
public:
    HMode hMode = HMode_Center;
    VMode vMode = VMode_Center;
    std::shared_ptr<sf::Text> text;
};

Text::Text(const sf::Vector2f &size):
    Entity(size),
    data(new TextData)
{
    data->text = std::make_shared<sf::Text>();
    data->text->setCharacterSize(18);
}

Text::~Text()
{
}

void Text::setCharacterSize(int pixelSize)
{
    data->text->setCharacterSize(pixelSize);
    onSizeChanged();
}

void Text::setTextColor(const sf::Color &color)
{
    data->text->setFillColor(color);
}

void Text::setTextColorAlpha(float alpha)
{
    auto color = data->text->getFillColor();
    color.a = std::clamp(alpha, 0.0f, 1.0f) * 255;
    data->text->setFillColor(color);
}

void Text::setText(const sf::String &text, bool resize)
{
    data->text->setString(text);
    if (resize) {
        auto box = data->text->getLocalBounds();
        setSize(box.width + 2 * TEXT_MARGIN, box.height + 2 * TEXT_MARGIN);
    }
    onPositionChanged();
    onSizeChanged();
}

sf::String Text::getText() const
{
    return data->text->getString();
}

void Text::setStyle(sf::Text::Style style)
{
    data->text->setStyle(style);
    onSizeChanged();
}

void Text::setHMode(HMode mode)
{
    data->hMode = mode;
    onSizeChanged();
}

HMode Text::getHMode() const
{
    return data->hMode;
}

void Text::setVMode(VMode mode)
{
    data->vMode = mode;
    onSizeChanged();
}

VMode Text::getVMode() const
{
    return data->vMode;
}

void Text::setFont(const std::string &file)
{
    auto manager = GET_COMPONENT(Application::getInstance(), FontManager);
    auto font = manager->loadFromFile(file);
    if (font) {
        data->text->setFont(*font);
        onSizeChanged();
    }
}

void Text::onPositionChanged()
{
    auto box = getTransform().transformRect(data->text->getLocalBounds());
    auto objectBox = getBoundingBox();
    auto newPosition = adjustPosition(objectBox, sf::Vector2f(box.width, box.height), data->hMode,
                                      data->vMode);
    newPosition.y -= box.top;
    newPosition.y += objectBox.top;
    data->text->setPosition(newPosition);
}

void Text::onSizeChanged()
{
    onPositionChanged();
}

void Text::onScaleChanged()
{
    data->text->setScale(getScale());
}

void Text::onDrawNode(sf::RenderTarget &target, sf::RenderStates states) const
{
    Entity::onDrawNode(target, states);
    target.draw(*data->text);
}

PTree Text::serialize()
{
    PTree node;
    node.add("hmode", toString(data->hMode));
    node.add("vmode", toString(data->vMode));
    node.add_child("Entity", Entity::serialize());
    return node;
}

void Text::deserialize(const PTree &node)
{
}
